package com.ease.framework.gef4p.figures.impl.edge {
   import com.ease.framework.figures.IFigure;
   import com.ease.framework.gef4p.figures.INodeFigure;
   import com.ease.framework.gef4p.figures.edge.IBendAnchor;

   import flash.events.MouseEvent;
   import flash.geom.Point;

   import mx.controls.Image;
   import mx.core.UIComponent;

   public class BendAnchor extends UIComponent implements IBendAnchor {
      private var _source:Bend;
      private var _target:Bend;
      private var img:Image;
      private var _manager:BendAnchorManager;

      public function BendAnchor(manager:BendAnchorManager, _source:Bend = null, _target:Bend = null) {
         super();
         this._source = _source;
         this._target = _target;
         this.x = (_source.x + _target.x) / 2 - 5;
         this.y = (_source.y + _target.y) / 2 - 5;
         this.width = 10;
         this.height = 10;
         this._manager = manager;
      }

      /**
       * 表示当Bend被加入到Edge中的时候，所发生的行为.
       **/
      override protected function createChildren():void {
         super.createChildren();
         this.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
         img = new Image();
         img.source = null;
         img.x = -10;
         img.y = -10;
         img.width = 20;
         img.height = 20;
         this.addChild(img);
      }


      public function mouseDown(event:MouseEvent):void {
         this.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
         this.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
         this.startDrag();
      }

      private function mouseMove(event:MouseEvent):void { //需要根据实际情况调整规则
         if (_source != _target) {
            var bend:Bend = new Bend();
            bend.x = this.parent.mouseX;
            bend.y = this.parent.mouseY;
            _source.setNext(bend);
            bend.setFront(_source);
            _target.setFront(bend);
            bend.setNext(_target);
            (this.parent as EdgeFigure).addChild(bend);
            (this.parent as EdgeFigure).bends.addItem(bend);

            var anchor:BendAnchor = new BendAnchor(_manager, _source, bend);
            _manager.bendAnchors.addItem(anchor);
            (this.parent as EdgeFigure).addChild(anchor);
            anchor.visible = this.visible;

            anchor = new BendAnchor(_manager, bend, _target);
            _manager.bendAnchors.addItem(anchor);
            (this.parent as EdgeFigure).addChild(anchor);
            anchor.visible = this.visible;

            this._source = bend;
            this._target = bend;
         }
         if (_source == _target) {
            _source.x = this.parent.mouseX;
            _source.y = this.parent.mouseY;
         }
         updateDisplay();
         (this.parent as EdgeFigure).invalidateDisplayList();
      }

      private function mouseUp(event:MouseEvent):void {

         this.stopDrag();
         this.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
         this.removeEventListener(MouseEvent.MOUSE_UP, mouseUp);

         if (_source == _target) {
            _source.x = this.parent.mouseX;
            _source.y = this.parent.mouseY;
         }

         var front:Bend = _source.getFront();
         var next:Bend = _source.getNext();
         var frontAnchor:BendAnchor = _manager.findBendAnchor(front, _source);
         var nextAnchor:BendAnchor = _manager.findBendAnchor(_source, next);
         if (frontAnchor != null && nextAnchor != null && (this.parent as EdgeFigure).mergeBendofLine(_source)) {
            this._source = front;
            this._target = next;
            frontAnchor.visible = false;
            nextAnchor.visible = false;
            _manager.bendAnchors.removeItemAt(_manager.bendAnchors.getItemIndex(frontAnchor));
            _manager.bendAnchors.removeItemAt(_manager.bendAnchors.getItemIndex(nextAnchor));
            (this.parent as EdgeFigure).removeChild(frontAnchor);
            (this.parent as EdgeFigure).removeChild(nextAnchor);
            frontAnchor = null;
            nextAnchor = null;
         }
         //check right angle
         maintainWithRightAngle();

         updateDisplay();
         (this.parent as EdgeFigure).invalidateDisplayList();
      }

      public static const maintainPixes:Number = 20;

      private function maintainWithRightAngle():void {
         //如果是两个bend的中间点，不处理
         if (_source != _target)
            return;

         //check null
         if (_source == null || target == null)
            return;

         //create local var
         var current:Bend = _source;
         var front:Bend = current.getFront();
         var next:Bend = current.getNext();


         var front_x:Number, front_y:Number, next_x:Number, next_y:Number;

         //set value for front_x,font_y,next_x,next_y
         if (front.getFront()) {
            front_x = front.x;
            front_y = front.y;
         }
         else {
            var source:INodeFigure = (this.parent as EdgeFigure).source;
            if (source) {
               var p:Point = getNodePoint(source);
               front_x = p.x;
               front_y = p.y;
            }
            else {
               return;
            }
         }
         if (next.getNext()) {
            next_x = next.x;
            next_y = next.y;
         }
         else {
            var target:INodeFigure = (this.parent as EdgeFigure).target;
            if (target) {
               p = getNodePoint(target);
               next_x = p.x;
               next_y = p.y;
            }
            else {
               return;
            }
         }

         //compute delta
         var frontDeltaX:Number = Math.abs(front_x - current.x);
         var frontDeltaY:Number = Math.abs(front_y - current.y);
         var nextDeltaX:Number = Math.abs(next_x - current.x);
         var nextDeltaY:Number = Math.abs(next_y - current.y);

         //maintain x
         if (frontDeltaX < nextDeltaX) {
            if (frontDeltaX <= maintainPixes) {
               current.x = front_x;
            }
         }
         else {
            if (nextDeltaX <= maintainPixes) {
               current.x = next_x;
            }
         }

         //maintain y
         if (frontDeltaY < nextDeltaY) {
            if (frontDeltaY <= maintainPixes) {
               current.y = front_y;
            }
         }
         else {
            if (nextDeltaY <= maintainPixes) {
               current.y = next_y;
            }
         }
      }

      private function getNodePoint(fig:INodeFigure):Point {
         var temp:Point = fig.parent.localToGlobal(new Point(fig.x, fig.y));
         temp = (this.parent as EdgeFigure).parent.globalToLocal(temp);

         var retPoint:Point = new Point();
         retPoint.x = temp.x + fig.width / 2;
         retPoint.y = temp.y + fig.height / 2;

         return retPoint;
      }

      private function updateDisplay():void {
         this.x = (_source.x + _target.x) / 2 - 5;
         this.y = (_source.y + _target.y) / 2 - 5;
         var frontAnchor:BendAnchor = _manager.findBendAnchor(_source.getFront(), _source);
         var nextAnchor:BendAnchor = _manager.findBendAnchor(_target, _target.getNext());
         this.invalidateDisplayList();
         if (frontAnchor != null) {
            frontAnchor.invalidateDisplayList();
         }
         if (nextAnchor != null) {
            nextAnchor.invalidateDisplayList();
         }
      }


      override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
         super.updateDisplayList(unscaledWidth, unscaledHeight);
         if (_source != _target) {
            this.x = (_source.x + _target.x) / 2 - 5;
            this.y = (_source.y + _target.y) / 2 - 5;
         }
         graphics.lineStyle(2, 0x03689A);
         graphics.beginFill(0xF4F6FF, 0.7);
         graphics.drawRect(0, 0, 10, 10);
         graphics.endFill();

      }


      public function set source(s:Bend):void {
         _source = s;
      }

      public function set target(t:Bend):void {
         _target = t;
      }

      public function findFigureAt(stageX:Number, stageY:Number):IFigure {
         return this;
      }

      public function get source():Bend {
         return _source;
      }

      public function get target():Bend {
         return _target;
      }

      public function clear():void {
         this.removeChild(img);
         img.source = null;
         img = null;
      }
   }
}